/*
carryforward.ado  7-29-2004

David Kantor
Institute for Policy Studies; Johns Hopkins University


Given a series of data in long shape, make an alternative version that
carries-forward values to fill in for missings.

This was originally in ..\psid003\prep264.do (with some hard-codings).

It would be nice to be able to enforce either stability or uniquness in the
sort.  But presently, we can't.  I've sent messages to Stata about this
(7-21- & 7-29-2004).  For now, we let the calling routine pre-sort it, or
just know that varlist2 (which is presumably used in the invocation) makes
a key with varlist1.

I have asked for a -unique- and/or -stable- option -- as well as access to
varlist2.  As soon as these become availble, use them in the calls to this.

Same for gen_tail, from which some code was borrowed.

4-6-2005: adding -if- and -in-.

2013feb6 attempting to make this handle multiple vars -- as requested from a
user several years ago.
2013feb15: adding the -strict- option.

2013apr19: adding dynamic_condition option.
2013apr24: just editing "*! version"

2013may4: change from @val to @.
2013july25: use clonevar; changed the use of notes and labelling; cleaned out unnecessary code (gen_orig);

2014may16: nonotes option.
2016jan15: ~~attempting to implement an extmiss option 

*/

*! version 4.5 2016jan15
* previous 4.4 2014may16
* previous 4.3 2013july25
* previous 4.2 2013apr24
* previous 4.1 2013feb15
* previous 3.2; 4-6-2005
* previous  3; 8-11-2004




program def carryforward, byable(onecall)
version 8.2

syntax varlist [if] [in], [gen(namelist) replace cfindic(namelist) back carryalong(varlist) strict ///
	dynamic_condition(string) debug nonotes extmiss]
marksample touse, novarlist

/*
cfindic is an indicator -- that a value is carried-forward (or back).

-back- is just some info affecting for the var label -- in case the actual
direction is backward instead of forward.  It does not control which direction
the carry operation goes; that always goes forward.  But there may be times
that you go backwards by giving it a sort variable that is the negative of
another.  For example,
 gen int negyear = -year
 bysort id (negyear): carryforward m, gen(m2) back

dynamic_condition allows you to put conditions on what gets carried, based on
values that evolve in the process of carrying the data.
e.g. dynamic_condition(var1[_n-1] < var2).
You can use @ to represent the value being carried. It represents `ggg'[_n-1]
where `ggg' is the variable being carried.

extmiss: treat extended missing values as legitimate; carry values into . only,
and potentially carry extended missing values.

*/




if "`gen'"=="" & "`replace'" =="" {
 disp as err "you must specify either gen or replace"
 exit 198
}
if "`gen'"~="" & "`replace'" ~="" {
 disp as err "you may not specify both gen and replace"
 exit 198
}


local fwdback
if "`back'" ~= "" {
 local fwdback " (backward)"
}


local numvars: list sizeof varlist
local numgens: list sizeof gen
local numcfindic: list sizeof cfindic

if "`carryalong'" ~= "" & `numvars' >1 {
	disp as err "carryalong may not be specified if varlist has more than one variable"
	exit 198
} 

if `numgens' >0 {
	confirm new var `gen'
	if `numgens' ~= `numvars' {
		disp as err "there must be as many variables in gen as in varlist"
		exit 198
	} 
}

if `numcfindic' >0 {
	confirm new var `cfindic'
	if `numcfindic' ~= `numvars' {
		disp as err "there must be as many variables in cfindic as in varlist"
		exit 198
	} 
	local overlap: list cfindic & gen
	if "`overlap'" ~= "" {
		disp as err "cfindic and gen may not have elements in common"
		exit 198
	}
}


if _by() {
	local by "by `_byvars' :"
}

if "`strict'" ~= "" {
	local strictcondition " & `touse'[_n-1]"
}

local jj = 1
foreach v of local varlist {

	local type1: type `v'

	local ggg: word `jj' of `gen'
	local ggo "`ggg'"
	local ccc: word `jj' of `cfindic'

	if "`ggg'"~="" {
		quietly clonevar `ggg' = `v'
	}
	else { // must be -replace-
		local ggg "`v'" // and operate directly in `v' under the name ggg.
		if "`ccc'" ~= "" | "`carryalong'" ~= "" {
			tempvar origvalues
			quietly gen `type1' `origvalues' = `v'
		}
	}

	disp "`ggg': ", _continue

	local dynamic_condition2
	if "`dynamic_condition'" ~= "" {
		local dynamic_condition2 " & (`=subinstr("`dynamic_condition'", "@", "`ggg'[_n-1]", .)')"
	}
	local numeric 0
	capture confirm numeric var `ggg'
	if ~_rc {
		local numeric 1
	}
	local misvalcondition
	if "`extmiss'" == "" | ~`numeric' {
		local misvalcondition "mi(`ggg') & ~mi(`ggg'[_n-1])"
	}
	else {
		local misvalcondition "(`ggg'==.) & (`ggg'[_n-1]~=.)"
	}

	if "`debug'" ~= "" {
		disp "~~~~"
		disp "`by' replace `ggg' = `ggg'[_n-1] if _n>1 & `touse' & `misvalcondition' `strictcondition' `dynamic_condition2'"
	}

	`by' replace `ggg' = `ggg'[_n-1] if _n>1 & `touse' & `misvalcondition' ///
		`strictcondition' `dynamic_condition2'

	if "`ccc'" =="" & "`carryalong'" ~= "" {
			/* Need ccc, but make it a temp */
			tempvar ccc
		}

	if "`ccc'" ~= "" {
		if "`ggo'"~="" {
			gen byte `ccc' = `ggg' ~= `v'
		}
		else { // must be -replace-
			gen byte `ccc' = `ggg' ~= `origvalues'
		}
		label var `ccc' "`ggg' has a carryforward`fwdback' value"
		assert ~mi(`ggg') if `ccc'
	}
	if "`notes'" == "" {
		notes `ggg': subjected to a carryforward`fwdback' operation
	}
	if "`carryalong'" ~= "" {
		tempvar t002
		foreach var of local carryalong {
			local type2: type `var'
			quietly gen `type2' `t002' = `var'
			quietly `by' replace `var' = `var'[_n-1] if _n>1 & `ccc'
			quietly count if `var' ~= `t002'
			local nchanges = r(N)
			disp as txt "(`var': `nchanges' changes made)"
			if "`notes'" == "" {
				notes `var': subjected to a carryforward`fwdback' operation as a carryalong variable, along with `v'
			}
			drop `t002'
		}
	}

	local ++jj
} /* end main loop */
	
end // carryforward
